package com.zyj.benchmark.sample;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.concurrent.TimeUnit;


/**
 * @BenchmarkMode 是测试模式, 输出结果的时候, 会按照测试模式给出不一样的报告
 * @OutputTimeUnit(TimeUnit.DAYS) 也是规范输出结果的时间的格式, 指定时间单位
 */
@Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)//预热次数和时间
@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)//测试次数和时间
public class Sample_02_BenchmarkMode {


    @Benchmark
    @BenchmarkMode(Mode.Throughput) //吞吐量测试, 输出报告: 每单位时间该方法会执行多少次
    @OutputTimeUnit(TimeUnit.DAYS) //输出报告的时间单位
    public void measureThroughput() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }


    @Benchmark
    @BenchmarkMode(Mode.AverageTime) //平均耗时测试, 输出报告: 每次操作耗时
    @OutputTimeUnit(TimeUnit.SECONDS) //耗时的单位
    public void measureAvgTime() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }


    @Benchmark
    @BenchmarkMode(Mode.SampleTime) //抽样测试, 输出报告: 会在执行过程中采样(每次操作耗时), 最快的, 50%快的, 90%, 95%, 99%, 99.9%, 99.99%, 100%
    @OutputTimeUnit(TimeUnit.SECONDS)
    public void measureSamples() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
        //输出内容:
        //正常情况应该是个正态分布
        //Benchmark                                                      Mode  Cnt  Score   Error  Units
        //Sample2_BenchmarkMode.measureSamples                         sample   47  0.109 ± 0.001   s/op
        //Sample2_BenchmarkMode.measureSamples:measureSamples·p0.00    sample       0.101           s/op
        //Sample2_BenchmarkMode.measureSamples:measureSamples·p0.50    sample       0.109           s/op
        //Sample2_BenchmarkMode.measureSamples:measureSamples·p0.90    sample       0.110           s/op
        //Sample2_BenchmarkMode.measureSamples:measureSamples·p0.95    sample       0.110           s/op
        //Sample2_BenchmarkMode.measureSamples:measureSamples·p0.99    sample       0.111           s/op
        //Sample2_BenchmarkMode.measureSamples:measureSamples·p0.999   sample       0.111           s/op
        //Sample2_BenchmarkMode.measureSamples:measureSamples·p0.9999  sample       0.111           s/op
        //Sample2_BenchmarkMode.measureSamples:measureSamples·p1.00    sample       0.111           s/op
    }


    @Benchmark
    @BenchmarkMode(Mode.SingleShotTime) //冷启动测试, 设置了这个, 此方法在一轮中只会运行一次, 这个模式主要是为了测试冷启动的性能
    @OutputTimeUnit(TimeUnit.SECONDS) //输出单位秒
    public void measureSingleShot() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
        //Benchmark                                Mode  Cnt  Score   Error  Units
        //Sample2_BenchmarkMode.measureSingleShot    ss       0.101           s/op
    }


    @Benchmark
    @BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime, Mode.SingleShotTime}) //四种都会测, 并都会输出
    @OutputTimeUnit(TimeUnit.SECONDS)
    public void measureMultiple() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }


    @Benchmark
    @BenchmarkMode(Mode.All) //每种模式都测一下
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureAll() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }


    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(Sample_02_BenchmarkMode.class.getSimpleName()).forks(1).build();
        new Runner(opt).run();
    }
}
